package post

import (
	"community-service/cmd/api/internal/models/model"
	"community-service/cmd/api/internal/svc"
	"community-service/cmd/api/internal/types"
	e "community-service/pkg/errorx"
	"context"
	"fmt"
	user "gitee.com/vzerx/proto-contracts/auth"
	"google.golang.org/grpc/codes"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserGetPostLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewUserGetPostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserGetPostLogic {
	return &UserGetPostLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UserGetPostLogic) UserGetPost(req *types.PostReq) (*types.UserPostRsp, error) {

	postQuery := l.svcCtx.DB.WithContext(l.ctx).Model(&model.CsCommunityPost{}).
		Joins("post").
		Joins(fmt.Sprintf("INNER JOIN %s topic ON post.topic_id = topic.id", model.TableNameCsCommunityTopic)).
		Joins(fmt.Sprintf("LEFT JOIN %s approve ON approve.post_id = post.id", model.TableNameCsCommunityPostApprove)).
		Joins(fmt.Sprintf("LEFT JOIN %s exp ON exp.post_id = post.id", model.TableNameCsCommunityPostExperimentMap)).
		Joins(fmt.Sprintf("LEFT JOIN %s comment ON comment.post_id = post.id", model.TableNameCsCommunityPostComment)).
		Joins(fmt.Sprintf("LEFT JOIN %s my_approve ON approve.post_id = post.id AND approve.create_user = %d",
			model.TableNameCsCommunityPostApprove, req.UserProfile.UserId)).
		Where("post.id = ?", req.Id).
		Select(
			"post.id", "post.topic_id", "post.title", "post.content", "post.status",
			"topic.name topic_name",
			"post.is_topped", "post.is_selected", "post.is_official",
			"post.view_count", "post.reason", "post.create_user", "post.create_username",
			"IFNULL(COUNT(DISTINCT approve.id), 0) as approve_count",
			fmt.Sprintf("CASE WHEN post.create_user = %d THEN 1 ELSE 0 END as owner", req.UserProfile.UserId),
			"CASE WHEN my_approve.id IS NOT NULL THEN 1 END is_approved",
			"IFNULL(COUNT(DISTINCT comment.id), 0) as comment_count",
			"UNIX_TIMESTAMP(post.created_at) as created_at",
			"UNIX_TIMESTAMP(post.updated_at) as updated_at",
			"IFNULL(exp.experiment_id, 0) as experiment_id",
			"IFNULL(exp.experiment_name, '') as experiment_name",
			"IFNULL(exp.course_resource_id, '') as course_resource_id",
			"IFNULL(exp.chapter_ref_id, '') as chapter_ref_id",
		)

	// 临时结构体接收查询结果
	type PostWithExperiment struct {
		types.UserPostRsp
		MenuName         string `json:"menu_name"`
		TopicName        string `json:"topic_name"`
		ExperimentId     int64  `json:"experiment_id"`
		ExperimentName   string `json:"experiment_name"`
		ChapterRefId     string `json:"chapter_ref_id"`
		CourseResourceId string `json:"course_resource_id"`
	}

	var raw PostWithExperiment
	if err := postQuery.
		Group("post.id").
		Order("post.is_topped DESC, post.is_selected DESC, post.is_official DESC, post.created_at DESC").
		Offset((req.PageNum - 1) * req.PageSize).
		Limit(req.PageSize).
		Find(&raw).Error; err != nil {
		return nil, e.NewGrpcErr(codes.Internal, e.DBError)
	}

	// 为空 || 不是自己的且不为上架
	if raw.Id == 0 || (!raw.Owner && raw.Status != types.PostTypeShelved) {
		return nil, e.NewGrpcErr(codes.NotFound, e.PostNotFound)
	}

	resp := &types.UserPostRsp{
		PostRsp: types.PostRsp{
			Id:      raw.Id,
			Title:   raw.Title,
			Content: raw.Content,
			MenuId:  raw.MenuId,
			TopicId: raw.TopicId,
			Status:  raw.Status,
			Reason:  raw.Reason,
			Topic: &types.TopicRsp{
				Id:   raw.TopicId,
				Name: raw.TopicName,
			},
			Menu: &types.MenuRsp{
				Id:   raw.MenuId,
				Name: raw.MenuName,
			},
			IsTopped:       raw.IsTopped,
			IsSelected:     raw.IsSelected,
			IsOfficial:     raw.IsOfficial,
			Owner:          raw.Owner,
			CreateUser:     raw.CreateUser,
			CreateUsername: raw.CreateUsername,
			CreatedAt:      raw.CreatedAt,
			UpdatedAt:      raw.UpdatedAt,
			Author: &types.AuthorRsp{
				Id:   raw.CreateUser,
				Name: raw.CreateUsername,
			},
			IsApproved:   raw.IsApproved,
			ApproveCount: raw.ApproveCount,
			ViewCount:    raw.ViewCount,
			CommentCount: raw.CommentCount,
		},
	}

	if raw.ExperimentId != 0 {
		resp.Experiment = &types.Experiment{
			Id:               raw.ExperimentId,
			Name:             raw.ExperimentName,
			CourseResourceId: raw.CourseResourceId,
			ChapterRefId:     raw.ChapterRefId,
		}
	}

	userInfo, err := l.svcCtx.User.GetUserInfo(l.ctx, &user.UserInfoReq{UserId: raw.CreateUser})
	if err == nil {
		resp.Author = &types.AuthorRsp{
			Id:            userInfo.UserId,
			Name:          userInfo.UserName,
			Sex:           userInfo.Sex,
			Avatar:        userInfo.Avatar,
			CollageName:   userInfo.CollageName,
			SecondOrgName: userInfo.SecOrgName,
			OrgName:       userInfo.OrgName,
		}
	}

	// 查询最后一个回复的用户
	var lastComment model.CsCommunityPostComment

	if err := l.svcCtx.DB.WithContext(l.ctx).Model(&lastComment).
		Where("post_id = ?", raw.Id).
		Order("created_at DESC").
		Limit(1).
		Find(&lastComment).Error; err != nil {
		return nil, e.NewGrpcErr(codes.Internal, e.DBError)
	}

	// 如果有最后回复人
	if lastComment.ID != 0 {
		resp.LatestAnswerUser = &types.AuthorRsp{
			Id:     lastComment.CreateUser,
			Name:   lastComment.CreateUsername,
			Avatar: "",
		}

		// 查询详细信息
		userInfo, err = l.svcCtx.User.GetUserInfo(l.ctx, &user.UserInfoReq{
			UserId: lastComment.CreateUser,
		})
		if err == nil {
			resp.LatestAnswerUser = &types.AuthorRsp{
				Id:            userInfo.UserId,
				Name:          userInfo.UserName,
				Sex:           userInfo.Sex,
				Avatar:        userInfo.Avatar,
				CollageName:   userInfo.CollageName,
				SecondOrgName: userInfo.SecOrgName,
				OrgName:       userInfo.OrgName,
			}
		}
	}

	// 更新查看次数
	_ = l.svcCtx.DB.WithContext(l.ctx).Model(&model.CsCommunityPost{}).Where("id = ?", req.Id).Update("view_count", resp.ViewCount+1).Error
	return resp, nil

}
